package com.zhou.hot.update;

/**
 * Created by zhouyongjun on 2020/4/15
 */

import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import com.zhou.hot.util.HotResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.util.regex.Pattern;


public class HotUpdate
{
    private HotUpdateConfig config;
    private static HotUpdate instance;
    private final String AGENT_JAR_PATH = "E:\\gitee\\public\\hot.update\\hot_update\\HotLoadAgent.jar";
    private final String PID_FILE = "../bin/pid.RedAlert";
    private final Logger logger = LoggerFactory.getLogger("hot.update");
    private Pattern numPattern = Pattern.compile("^[-\\+]?[\\d]*$");

    private  HotUpdate(){}
    public static HotUpdate getInstance() {
        if (instance == null) {
            instance = new HotUpdate();
        }
        return instance;
    }

    /*public static void main(String[] args) throws IOException {
            String pid = null;
            if(args != null && args.length > 0)
            {
                pid = args[0];
            }
            if(pid == null || pid.isEmpty())
            {
                Scanner sc = null;
                try {
                    sc = new Scanner(System.in);
                    logger.info("输入进程id");
                    while (true) {
                        pid = sc.nextLine();
                        if (numPattern.matcher(pid).matches()) break;
                        logger.info("输入错误,请重新输入!");
                    }
                } catch (Exception e) {
                    logger.error("",e);
                }finally {
                    sc.close();
                }
            }
            logger.info("进程ID:"+pid);
            hotLocal(pid);
        }*/
    public  void init()
    {
        try {
            config = new HotUpdateConfig();
            config.load();
        } catch (Exception e) {
            logger.error("",e);
        }
    }

    /**
     *
     * @return
     */
    public  HotResult hotLocalSelf()
    {
        int pid = getSelfProcessID();
        HotResult result =  hotLocal(String.valueOf(pid));
        logger.info("hot update result : isSucc="+result.isSucc()+",msg=" + result.getMsg());
        return result;
    }

    public  HotResult hotLocal(String pid) {
        VirtualMachine vm = null;
        try {
            init();
            if (pid == null || pid.isEmpty()) {
                pid = config.getPidFromFile();
            }
            if (pid == null || pid.isEmpty())
            {
                return HotResult.RESULT_FAIL;
            }
            logger.info("hot update 热更新 进程："+pid+" 开始...");
            logger.info("hot update 热更新 Agent jar: "+config.getHotLoadAgentJar());
            vm = VirtualMachine.attach(pid);
            for (VirtualMachineDescriptor virtualMachineDescriptor : VirtualMachine.list()) {
//                virtualMachineDescriptor.id() == pid;
            }
            logger.info("hot update this classloader= " + HotUpdate.class.getClassLoader()+","+HotUpdate.class.getClassLoader().getParent());
            logger.info("hot update thread  classloader= " + Thread.currentThread().getContextClassLoader()+","+Thread.currentThread().getContextClassLoader().getParent());
            logger.info("hot update  vm classloader= " + vm.getClass().getClassLoader()+","+vm.getClass().getClassLoader().getParent());
            vm.loadAgent(config.getHotLoadAgentJar());
            return HotResult.RESULT_SUCC;
        } catch (Exception e) {
            logger.error("hot update VirtualMachine loadAgent 失败",e);
            return HotResult.RESULT_FAIL;
        } finally {
            try {
                logger.info("hot update 热更新 进程："+pid+" 结束...");
                if (vm != null ) {
                    vm.detach();
                }
            } catch (Exception e) {
               logger.error("hot update VirtualMachine detach 失败",e);
            }
        }

    }

    /*public static boolean confirmCMD()
    {
        while (true)
        {
            String input = sc.nextLine();
            if (input.equals("yes"))
                return true;
            if ((input.equals("no")) || (input.equals("quit"))) {
                return false;
            }
            logger.info("未知命令,请重新输入[yes/no]");
        }
    }*/

    /**
     * 获取本身进程ID
     * @return
     */
    public int getSelfProcessID()
    {
        //运行管理
        int id = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
        return id;
    }
}